package com.imooc.mymall.service.impl;

import com.alibaba.excel.EasyExcelFactory;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.imooc.mymall.domain.common.PageQuery;
import com.imooc.mymall.domain.common.PageResult;
import com.imooc.mymall.domain.dto.UserDTO;
import com.imooc.mymall.domain.dto.UserExportDTO;
import com.imooc.mymall.domain.dto.UserQueryDTO;
import com.imooc.mymall.service.ExcelExportService;
import com.imooc.mymall.service.FileService;
import com.imooc.mymall.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.checkerframework.checker.units.qual.A;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.OutputStream;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * <h1>Excel导出服务接口实现类</h1>
 * @Author: crowsjian
 * @Date: 2020/7/18 0:56
 */
@Service
@Slf4j
public class ExcelExportServiceImpl implements ExcelExportService {

    @Autowired
    private FileService fileService;

    @Autowired
    private UserService userService;

    /**
     * <h2>执行数据库查询，和Excel导出，将导出的数据写入到OutputStream当中</h2>
     * @param outputStream
     * @param query
     */
    public void export(OutputStream outputStream,UserQueryDTO query){
        // step1. 需要创建一个EasyExcel导出对象
        ExcelWriter excelWriter = EasyExcelFactory.write(
                outputStream,
                UserExportDTO.class)
                .build();
        // step2. 分批加载数据
        PageQuery<UserQueryDTO> pageQuery = new PageQuery<>();
        pageQuery.setQuery(query);
        pageQuery.setPageSize(2);
        int pageNo = 0;
        PageResult<List<UserDTO>> pageResult;
        do{
            // 先累加 再赋值
            pageQuery.setPageNo(++pageNo);
            log.info("开始导出第[{}]页数据!",pageNo);
            pageResult = userService.query(pageQuery);
            // 数据转换 UserDTO->UserExportDTO
            List<UserExportDTO> userExportDTOList = Optional.ofNullable(pageResult.getData())
                    .map(List::stream)
                    .orElseGet(Stream::empty)
                    .map(userDTO->{
                        UserExportDTO userExportDTO = new UserExportDTO();
                        // 转换
                        BeanUtils.copyProperties(userDTO,userExportDTO);
                        return userExportDTO;
                    }).collect(Collectors.toList());
            // step 3. 导出分批加载的数据
            // 将数据写出到不同的sheet页中
            WriteSheet writeSheet = EasyExcelFactory.writerSheet(pageNo,"第"+pageNo+"页").build();
            excelWriter.write(userExportDTOList,writeSheet);
            log.info("结束导出第[{}]页数据!",pageNo);
            //总页数大于当前页数 说明还有数据 需要再次执行
        }while (pageResult.getPageNum()>pageNo);
        // step4. 收尾，执行finish，才会关闭Excel流文件
        excelWriter.finish();
        log.info("完成导出！");
    }

    @Override
    public void export(UserQueryDTO query, String filename) {
        // 输出流
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        // step1 实现数据导出的Excel
        export(outputStream,query);
        // 输入流
        ByteArrayInputStream inputStream = new ByteArrayInputStream(outputStream.toByteArray());
        // step2 实现文件上传
        fileService.upload(inputStream,filename);
    }

    /**
     * <h2>借助@Async,使用线程池执行方法</h2>
     * @param query
     * @param filename
     */
    @Async("exportServiceExecutor")
    @Override
    public void asyncExport(UserQueryDTO query, String filename) {
        export(query,filename);
    }
}
